package priv.zgh.forum.chat.websocket;

import com.google.gson.Gson;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import priv.zgh.forum.auth.entity.User;
import priv.zgh.forum.auth.service.UserService;
import priv.zgh.forum.auth.service.impl.UserServiceImpl;
import priv.zgh.forum.chat.vo.ChatContentVo;
import priv.zgh.forum.exception.ForumException;
import priv.zgh.forum.utils.SpringUtils;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

@ServerEndpoint(value = "/websocket/{userId}")
@Lazy // 没有懒加载就会造成bean没有没实例化的时候就被填充进去
@Component
public class MyWebSocket {

    //spring管理的都是单例（singleton）和 websocket （多对象）相冲突。
    //需要了解一个事实：websocket 是多对象的，每个用户的聊天客户端对应 java 后台的一个 websocket 对象，前后台一对一（多对多）实时连接，
    //所以 websocket 不可能像 servlet 一样做成单例的，让所有聊天用户连接到一个 websocket对象，这样无法保存所有用户的实时连接信息。
    //可能 spring 开发者考虑到这个问题，没有让 spring 创建管理 websocket ，而是由 java 原来的机制管理websocket ，所以用户聊天时创建的
    //websocket 连接对象不是 spring 创建的，spring 也不会为不是他创建的对象进行依赖注入，所以如果不用static关键字，每个 websocket 对象的 service 都是 null。
    private static UserService userService = SpringUtils.getBean(UserServiceImpl.class);

    /**
     * gosn
     */
    private static Gson gson = new Gson();

    /**
     * 在线人数
     */
    public static AtomicInteger onlineNumber = new AtomicInteger(0);

    /**
     * 所有的对象，每次连接建立，都会将我们自己定义的MyWebSocket存放到List中，
     */
    public static List<MyWebSocket> webSockets = new CopyOnWriteArrayList<MyWebSocket>();

    /**
     * 会话，与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 每个会话的用户
     */
    private User user;

    /**
     * 建立连接
     *
     * @param session
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        if (userId == null || "".equals(userId)) {
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
        onlineNumber.incrementAndGet();
        // 遍历所有的webSocket类,查找是否有相同的存在
        for (MyWebSocket myWebSocket : webSockets) {
            if (userId.equals(myWebSocket.user.getId())) {
                try {
                    // 已经存在了就把当前需要访问的session关闭
                    session.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return;
            }
        }
        this.session = session;
        System.out.println(userId);
        System.out.println(userService);
        List<User> users = userService.list(null);
        for(User item : users){
            System.out.println(item);
        }
        this.user = userService.getById(userId);
        if(this.user == null){
            throw new ForumException(20001,"当前用户id不存在!");
        }
        webSockets.add(this);
        System.out.println("有新连接加入！ 当前在线人数" + onlineNumber.get());
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose() {
        onlineNumber.decrementAndGet();
        webSockets.remove(this);
        System.out.println("有连接关闭！ 当前在线人数" + onlineNumber.get());
    }

    /**
     * 收到客户端的消息
     *
     * @param message 消息
     * @param session 会话
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("userId") String userId) {
        User userInfo = userService.getById(userId);
        if(userInfo == null) {
            throw new ForumException(20001, "当前用户id不存在!");
        }
        ChatContentVo chatContentVo = gson.fromJson(message,ChatContentVo.class);
        System.out.println(chatContentVo);
        System.out.println("来自" + user.getNickname() + "消息：" + message);
        // TODO:可以选择uuid
        if(chatContentVo.getUuid() == null || ("").equals(chatContentVo.getUuid())){
            pushMessage(userInfo, message, chatContentVo.getUuid());
        }
//        pushMessage(userInfo, message, null);
    }

    /**
     * 发送消息
     *
     * @param message 消息
     */
    public void sendMessage(String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 消息推送
     *
     * @param message
     * @param uuid    uuid为空则推送全部人员
     */
    public static void pushMessage(User user, String message, String uuid) {
        // 当uuid为空的时候就发送给所有人消息,如果不为空就遍历webSocket实例来寻找用户id为uuid的用户然后发送消息
        if (uuid == null || "".equals(uuid)) {
            for (MyWebSocket myWebSocket : webSockets) {
                myWebSocket.sendMessage(user.getNickname() + ":" + message);
            }
        } else {
            for (MyWebSocket myWebSocket : webSockets) {
                if (uuid.equals(myWebSocket.user.getId())) {
                    myWebSocket.sendMessage(message);
                }
            }
        }

    }
}
